package com.joysuch.wwyt.bp.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yitter.idgen.YitIdHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.joysuch.wwyt.bp.bean.investigate.SimpleTaskAssign;
import com.joysuch.wwyt.bp.bean.investigate.TaskSummarySearchBean;
import com.joysuch.wwyt.bp.bean.investigate.vo.AppInvestigateSummaryVo;
import com.joysuch.wwyt.bp.bean.vo.RiskPointSnapshotVo;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.entity.BpInvestigateTaskSummary;
import com.joysuch.wwyt.bp.entity.bean.RecordSearchBean;
import com.joysuch.wwyt.bp.entity.dto.BpInvestigateTaskSummaryDto;
import com.joysuch.wwyt.bp.entity.dto.CheckRecordDto;
import com.joysuch.wwyt.bp.entity.dto.UserTaskRecordDto;
import com.joysuch.wwyt.bp.entity.investigate.BpInvestigateRecord;
import com.joysuch.wwyt.bp.entity.investigate.BpInvestigateRecordItem;
import com.joysuch.wwyt.bp.entity.vo.AppCheckTaskVo;
import com.joysuch.wwyt.bp.entity.vo.CheckRecordVo;
import com.joysuch.wwyt.bp.entity.vo.NfcCheckTaskVO;
import com.joysuch.wwyt.bp.enums.*;
import com.joysuch.wwyt.bp.mapper.*;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.bp.repository.BpInvestigateRecordItemDao;
import com.joysuch.wwyt.bp.repository.BpInvestigateRecordRepository;
import com.joysuch.wwyt.bp.service.BpInvestigateRecordService;
import com.joysuch.wwyt.bp.service.BpInvestigateTaskAssignService;
import com.joysuch.wwyt.bp.service.BpInvestigateTaskSummaryService;
import com.joysuch.wwyt.common.bean.KLMapping;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.core.bean.SimpleIdMapping;
import com.joysuch.wwyt.core.bean.SimpleSelectListBean;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.entity.BaseConfig;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.enums.BaseConfigCodes;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.service.BaseRoleDataAuthService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.risk.bean.FenceData;
import com.joysuch.wwyt.risk.bean.FencePoint;
import com.joysuch.wwyt.risk.entity.RiskPoint;
import com.joysuch.wwyt.risk.entity.vo.RiskMeasureTypeNode;
import com.joysuch.wwyt.risk.enums.SignInMethodEnum;
import com.joysuch.wwyt.risk.mapper.RiskMeasureTypeMapper;
import com.joysuch.wwyt.risk.repository.RiskDistrictDao;
import com.joysuch.wwyt.risk.repository.RiskPointDao;
import com.joysuch.wwyt.risk.service.RiskMeasureTypeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zr
 * @since 2021-09-16
 */
@Service
@Slf4j
public class BpInvestigateTaskSummaryServiceImpl extends ServiceImpl<BpInvestigateTaskSummaryMapper, BpInvestigateTaskSummary> implements BpInvestigateTaskSummaryService {

    @Autowired
    private BpInvestigateTaskSummaryMapper summaryMapper;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private RiskMeasureTypeService riskMeasureTypeService;
    @Autowired
    private BpInvestigateRecordService bpInvestigateRecordService;
    @Autowired
    private BpInvestigateRecordRepository recordRepository;
    @Autowired
    private BpInvestigateTaskAssignService bpInvestigateTaskAssignService;
    @Autowired
    private BpInvestigateTaskAssignMapper assignMapper;
    @Autowired
    private BpInvestigateRecordItemDao recordItemDao;
    @Autowired
    private BpDepartDao departDao;
    @Autowired
    private RiskDistrictDao districtDao;
    @Autowired
    private BaseRoleDataAuthService authService;
    @Autowired
    private BpInvestigateTaskMapper taskMapper;
    @Autowired
    private BaseConfigService configService;
    @Autowired
    private BpInvestigateTaskHisMapper investigateHistoryMapper;
    @Autowired
    private RiskPointDao riskPointDao;
    @Autowired
    private RiskMeasureTypeMapper riskMeasureTypeMapper;
    @Autowired
    private BpInvestigateTaskHisMapper taskHisMapper;
    @Autowired
    private BpInvestigateTaskSummaryHisMapper taskSummaryHisMapper;

    @Override
    public ResultBean findRecordSummaryByPaging(TaskSummarySearchBean searchBean, boolean onlySelf) {
        Page<BpInvestigateTaskSummary> page = new Page<>(searchBean.getPage() + 1, searchBean.getSize());
        List<BpInvestigateTaskSummaryDto> list = new ArrayList<>();
        String companyCode = Context.getCompanyCode();
        Long tenantId = Context.getCurrentTenantId();
        // '全部记录'页面，查询所有人(权限内)的汇总
        Set<Long> auth = authService.findAuthDepartIdsByCurUser();
        // 无权限在直接返回
        if (CollectionUtil.isEmpty(auth)) {
            return new ResultBean();
        }
        searchBean.setAuthDepartIds(auth);
        builderSearchParam(searchBean);
        // 按人名模糊查询，人名不存在
        if (StringUtils.isNotBlank(searchBean.getCheckUserName()) && CollectionUtils.isEmpty(searchBean.getCheckUserIds())) {
            return ResultBean.success(new ArrayList<>());
        }
        boolean needAutograph=false;
        BaseConfig config = configService.findFirstConfig(BaseConfigCodes.AUTOGRAPH);
        if (config != null && config.getValue().equals("开启")) {
            needAutograph=true;
        }
        // app只查自己的，web查所有人的
        IPage<BpInvestigateTaskSummaryDto> summary = summaryMapper.findRecordSummaryByPaging(page, onlySelf ? Context.getCurrentUserId() : null, searchBean, companyCode, tenantId);
        Map<Long, String> map = new HashMap<>();
        if (needAutograph){
            if (CollectionUtils.isNotEmpty(summary.getRecords())) {
                List<Long> userIds = summary.getRecords().stream().filter(m ->m.getUserId()!=null&&m.getUserId()!=-1).map(m -> m.getUserId()).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(userIds)) {
                    map=getAutograph(userIds);
                }
            }
        }

        for (BpInvestigateTaskSummaryDto record : summary.getRecords()) {
            record.setCheckUserName(convertUserIdToName(Collections.singletonList(record.getUserId())));
            if (needAutograph){
                record.setAutograph(map.get(record.getUserId()));
            }
            list.add(record);
        }
        return ResultBean.pageData(list, summary.getTotal());
    }

    @Override
    public Page findHistorySummaryPage(TaskSummarySearchBean searchBean) {
        Page<BpInvestigateTaskSummary> page = new Page<>(searchBean.getPage() + 1, searchBean.getSize());
        String companyCode = Context.getCompanyCode();
        Long tenantId = Context.getCurrentTenantId();
        // '全部记录'页面，查询所有人(权限内)的汇总
        Set<Long> auth = authService.findAuthDepartIdsByCurUser();
        // 无权限在直接返回
        if (CollectionUtil.isEmpty(auth)) {
            return new Page();
        }
        searchBean.setAuthDepartIds(auth);
        //不进行count查询
        builderSearchParam(searchBean);
        // 按人名模糊查询，人名不存在
        if (StringUtils.isNotBlank(searchBean.getCheckUserName()) && CollectionUtils.isEmpty(searchBean.getCheckUserIds())) {
            return new Page();
        }
        Page<BpInvestigateTaskSummaryDto> summaryPage = summaryMapper.findHisRecordSummaryPage(page, searchBean, companyCode, tenantId);
        List<BpInvestigateTaskSummaryDto> summarys = summaryPage.getRecords();
        if (CollectionUtil.isNotEmpty(summarys)) {
            List<Long> taskIds = summarys.stream().filter(e -> e.getTaskId() != null).map(BpInvestigateTaskSummaryDto::getTaskId).collect(Collectors.toList());
            Set<Long> userIds = summarys.stream().map(BpInvestigateTaskSummaryDto::getUserId).collect(Collectors.toSet());
            List<BpInvestigateRecord> records = CollectionUtil.isEmpty(taskIds) ? null : investigateHistoryMapper.getRecordByTaskIds(taskIds);
            Map<Long, BpInvestigateRecord> recordMap = CollectionUtil.isEmpty(records) ? new HashMap<>() : records.stream().collect(Collectors.toMap(BpInvestigateRecord::getTaskId, e -> e));
            List<BaseUser> users = baseUserDao.getAllByIds(userIds);
            Map<Long, BaseUser> userMap = CollectionUtil.isEmpty(users) ? new HashMap<>() : users.stream().collect(Collectors.toMap(BaseUser::getId, u -> u));
            // recordId，user 转换
            summarys.forEach(summary -> {
                if (null != summary.getTaskId()) {
                    BpInvestigateRecord record = recordMap.get(summary.getTaskId());
                    if (null != record) {
                        summary.setRecordId(record.getId());
                    }
                }
                if (null != summary.getUserId()) {
                    BaseUser user = userMap.get(summary.getUserId());
                    if (null != user) {
                        summary.setCheckUserName(user.getRealName());
                    }
                }
                if (StringUtils.isBlank(summary.getExceptionProcessResult())) {
                    summary.setExceptionProcessResult(RepairStatus.NO_PROCESSING_REQUIRED.getDesc());
                }
            });
        }
        List<BpInvestigateTaskSummaryDto> records = summaryPage.getRecords();
        return summaryPage;
    }

    @Override
    public BpInvestigateTaskSummary findRecordBySummaryId(Long summaryId) {
        BpInvestigateTaskSummary summary = summaryMapper.selectById(summaryId);
        Date startTime = DateUtil.beginOfDay(summary.getCheckDate());
        DateTime endTime = DateUtil.beginOfDay(DateUtil.offsetDay(summary.getCheckDate(), 1));
        List<UserTaskRecordDto> userTaskRecords = summaryMapper.findUserTaskByDeadline(summary.getUserId(), startTime, endTime);
        List<String> exceptionProcessList = userTaskRecords.stream().map(UserTaskRecordDto::getRepairStatus).filter(ex -> StringUtils.isNotBlank(ex) && !RepairStatus.NO_RECTIFICATION_REQUIRED.getDesc().equals(ex)).collect(Collectors.toList());
        String exceptionHandleStatus = bpInvestigateRecordService.calculateExceptionHandleStatus(summary.getCheckResult(), exceptionProcessList);
        summary.setExceptionProcessResult(exceptionHandleStatus);
        return summary;
    }

    private void builderSearchParam(TaskSummarySearchBean searchBean) {
        if (searchBean.getCheckDate() != null) {
            Date searchStartTime = DateUtil.beginOfDay(searchBean.getCheckDate());
            Date searchEndTime = DateUtil.endOfDay(searchBean.getCheckDate());
            searchBean.setSearchStartTime(searchStartTime);
            searchBean.setSearchEndTime(searchEndTime);
        }
        if (StringUtils.isNotBlank(searchBean.getCheckUserName())) {
            List<Long> userIds = baseUserDao.findByNameLikeIgnoreDeleteStatus(searchBean.getCheckUserName());
            if (CollectionUtil.isNotEmpty(userIds)) {
                searchBean.setCheckUserIds(userIds);
            }
        }
    }

    @Override
    public IPage<BpInvestigateTaskSummaryDto> findTodaySummaryPaging(TaskSummarySearchBean searchBean) {
        // 查询日期为当天
        // searchBean.setCheckDate(new Date());
        Page<BpInvestigateTaskSummary> page = new Page<>(searchBean.getPage() + 1, searchBean.getSize());
        //不进行count查询
        page.setSearchCount(false);
        // '全部任务'页面，查询所有人(权限内)的汇总
        Long userId = Context.getCurrentUserId();
        Set<Long> authDepartIds = authService.findAuthDepartIdsByCurUser();
        // 无权限
        if (CollectionUtil.isEmpty(authDepartIds)) {
            return new Page<>();
        }
        searchBean.setAuthDepartIds(authDepartIds);
        String companyCode = Context.getCompanyCode();
        Long tenantId = Context.getCurrentTenantId();
        builderSearchParam(searchBean);
        // 按人名模糊查询，人名不存在
        if (StringUtils.isNotBlank(searchBean.getCheckUserName()) && CollectionUtils.isEmpty(searchBean.getCheckUserIds())) {
            return new Page<>();
        }
        Page<BpInvestigateTaskSummaryDto> summaryPage = summaryMapper.findTodaySummaryPage(page, searchBean, companyCode, tenantId);
        int count = summaryMapper.findTodaySummaryCount(searchBean, companyCode, tenantId);
        List<BpInvestigateTaskSummaryDto> records = summaryPage.getRecords();
        // 部门名称、是否本人的汇总
        if (CollectionUtil.isNotEmpty(records)) {
            Set<Long> departIds = records.stream().map(BpInvestigateTaskSummaryDto::getDepartId).collect(Collectors.toSet());
            List<BpDepart> departs = departDao.findByIdIn(new ArrayList<>(departIds));
            Map<Long, BpDepart> departMap = CollectionUtil.isNotEmpty(departs) ?
                    departs.stream().collect(Collectors.toMap(BpDepart::getId, d -> d))
                    : new HashMap<>();
            // 计划Id相关数据准备
            List<Long> taskIds = records.stream().filter(e -> SourceType.OLD.getValue().equals(e.getSourceType())).map(BpInvestigateTaskSummaryDto::getId).collect(Collectors.toList());
            List<SimpleIdMapping> planIdTaskIds = CollectionUtil.isNotEmpty(taskIds) ? taskMapper.getPlanIdByTaskIds(taskIds) : new ArrayList<>();
            Map<Long, Long> planIdTaskIdMap = planIdTaskIds.stream().collect(Collectors.toMap(SimpleIdMapping::getSourceId, SimpleIdMapping::getTargetId));

            records.forEach(record -> {
                if (record.getDepartId() != null) {
                    BpDepart depart = departMap.get(record.getDepartId());
                    record.setDepartName(null == depart ? Constant.EMPTY_STR : depart.getName());
                }
                if (SourceType.OLD.getValue().equals(record.getSourceType())) {
                    record.setPlanId(planIdTaskIdMap.get(record.getId()));
                }
                // 是否本人汇总，此字段决定是否可操作
                record.setCanHandle(userId.equals(record.getUserId()));
            });
        }
        summaryPage.setTotal(count);
        return summaryPage;
    }

    @Override
    public IPage<AppInvestigateSummaryVo> findTodaySummaryPagingApp(TaskSummarySearchBean searchBean) {
        searchBean.setCheckDate(new Date());
        Page<BpInvestigateTaskSummary> page = new Page<>(searchBean.getPage() + 1, searchBean.getSize());
        Long userId = Context.getCurrentUserId();
        builderSearchParam(searchBean);
        Page<AppInvestigateSummaryVo> result = summaryMapper.findTodaySummaryPageApp(page, userId, searchBean);
        List<AppInvestigateSummaryVo> list = result.getRecords();
        if (CollectionUtil.isNotEmpty(list)) {
            List<Long> taskIds = list.stream().filter(e -> SourceType.OLD.getValue().equals(e.getSourceType())).map(AppInvestigateSummaryVo::getId).collect(Collectors.toList());
            List<SimpleIdMapping> planIdTaskIds = CollectionUtil.isNotEmpty(taskIds) ? taskMapper.getPlanIdByTaskIds(taskIds) : new ArrayList<>();
            Map<Long, Long> planIdTaskIdMap = planIdTaskIds.stream().collect(Collectors.toMap(SimpleIdMapping::getSourceId, SimpleIdMapping::getTargetId));
            list.forEach(e -> {
                if (SourceType.OLD.getValue().equals(e.getSourceType())) {
                    e.setPlanId(planIdTaskIdMap.get(e.getId()));
                }
            });
        }
        return result;
    }

    private String convertUserIdToName(List<Long> userIds) {
        if (CollectionUtil.isEmpty(userIds)) {
            return null;
        }
        List<String> userNameList = baseUserDao.findRealNameByIdIn(userIds);
        return userNameList.stream().collect(Collectors.joining(Constant.SPLIT_COMMA));
    }

    @Override
    public BpInvestigateTaskSummary findByUserIdAndCheckDate(Long userId, Date checkDate) {
        return summaryMapper.findByUserIdAndCheckDate(userId, checkDate);
    }


    //根据任务记录的汇总id删除
    @Override
    public void deleteSummaryById(Long summaryId) {
        BpInvestigateTaskSummary summary = this.getById(summaryId);
        // summary表没有，则是从summary_history中取
        if (null == summary) {
            investigateHistoryMapper.deleteSummaryHistoryById(summaryId);
        }else {
            summary.setId(summaryId);
            summary.setDeleteFlag(DeleteFlag.DELETED.getCode());
            summaryMapper.updateById(summary);
        }

    }

    @Override
    public ResultBean getRecordByTaskSummaryId(RecordSearchBean recordSearchBean) {
        Page<CheckRecordDto> page = new Page<>(recordSearchBean.getPage() + 1, recordSearchBean.getSize());
        // 不进行count查询
        page.setSearchCount(false);
        recordSearchBean.setEndOfCheckDate(DateUtil.beginOfDay(DateUtil.offsetDay(recordSearchBean.getCheckDate(),1)));
        recordSearchBean.setTenentId(Context.getCurrentTenantId());
        recordSearchBean.setOrgCode(Context.getCompanyCode() + Constant.SQL_LIKE);
        // 获取分类筛选范围
        List<Long> riskMeasureTypeIds = new ArrayList<>();
        if (recordSearchBean.getRiskMeasureTypeId() != null) {
            riskMeasureTypeIds = riskMeasureTypeMapper.getAllIdsByPid(recordSearchBean.getRiskMeasureTypeId());
        }
        List<CheckRecordDto> recordDtos = summaryMapper.getRecordByPaging(page, recordSearchBean, riskMeasureTypeIds);
        // 未检的带上未检原因、去除完成时间、去除完成人（只web做转换）
        uncheckConvert(recordDtos);
        long count = summaryMapper.getRecordCount(recordSearchBean, riskMeasureTypeIds);
        ResultBean resultBean = ResultBean.pageData(convertDtoToVoBatch(recordDtos, Boolean.FALSE), count);
        return resultBean;
    }

    @Override
    public ResultBean getHistoryRecordPage(RecordSearchBean recordSearchBean) {
        Page<CheckRecordDto> page = new Page<>(recordSearchBean.getPage() + 1, recordSearchBean.getSize());
        // 不进行count查询
        page.setSearchCount(false);
        recordSearchBean.setEndOfCheckDate(DateUtil.beginOfDay(DateUtil.offsetDay(recordSearchBean.getCheckDate(),1)));
        recordSearchBean.setTenentId(Context.getCurrentTenantId());
        recordSearchBean.setOrgCode(Context.getCompanyCode() + Constant.SQL_LIKE);
        // 获取分类筛选范围
        List<Long> riskMeasureTypeIds = new ArrayList<>();
        if (recordSearchBean.getRiskMeasureTypeId() != null) {
            riskMeasureTypeIds = riskMeasureTypeMapper.getAllIdsByPid(recordSearchBean.getRiskMeasureTypeId());
        }
        List<CheckRecordDto> recordDtos = summaryMapper.getHistoryRecordByPaging(page, recordSearchBean, riskMeasureTypeIds);
        // 未检的带上未检原因、去除完成时间、去除完成人（只web做转换）
        uncheckConvert(recordDtos);
        long count = summaryMapper.getHistoryRecordCount(recordSearchBean, riskMeasureTypeIds);
        ResultBean resultBean = ResultBean.pageData(convertDtoToVoBatch(recordDtos, Boolean.TRUE), count);
        return resultBean;
    }

    @Override
    public List<SimpleSelectListBean> getSubscript() {
        RecordSearchBean recordSearchBean = new RecordSearchBean();
        recordSearchBean.setOrgCode(Context.getCompanyCode()+Constant.SQL_LIKE);
        recordSearchBean.setTenentId(Context.getCurrentTenantId());
        recordSearchBean.setCheckDate(DateUtil.beginOfDay(new Date()));
        recordSearchBean.setEndOfCheckDate(DateUtil.beginOfDay(DateUtil.offsetDay(recordSearchBean.getCheckDate(),1)));
        recordSearchBean.setUserId(Context.getCurrentUserId());
        List<SimpleSelectListBean> subscript = summaryMapper.getSubscript(recordSearchBean);
        return subscript;
    }

    // app端隐患排查
    public List<AppCheckTaskVo> getAppSubTimeTask(RecordSearchBean recordSearchBean) {
        recordSearchBean.setCheckDate(DateUtil.beginOfDay(new Date()));
        recordSearchBean.setEndOfCheckDate(DateUtil.endOfDay(recordSearchBean.getCheckDate()));
        recordSearchBean.setTenentId(Context.getCurrentTenantId());
        recordSearchBean.setOrgCode(Context.getCompanyCode() + Constant.SQL_LIKE);
        // app任务，需要按时间片分组，直接查全部不分页
        List<CheckRecordDto> recordDtos = null;
        List<CheckRecordVo> appTaskVos = null;
        List<String> cycleTypes = recordSearchBean.getCycleTypes();
        List<AppCheckTaskVo> result = null;
        if (cycleTypes.size() == 1 && recordSearchBean.getCycleTypes().contains("时")) {
            recordDtos = summaryMapper.getSimpleRecordByPaging(recordSearchBean);
            appTaskVos = castDtoToVo(recordDtos);
            result = generateAppSubTimeList(appTaskVos, false);
        }else {
            recordDtos = summaryMapper.getRecordByPaging(recordSearchBean);
            appTaskVos = convertDtoToVoBatch(recordDtos, Boolean.FALSE);
            result = generateAppSubTimeList(appTaskVos, true);
        }
        return result;
    }

    @Override
    public List<AppCheckTaskVo.PointTaskGroup> getTaskIdsById(List<Long> taskIds) {
        List<CheckRecordDto> taskDetails = summaryMapper.getTaskRecordByIds(taskIds);
        List<CheckRecordVo> taskDetailVo = convertDtoToVoBatch(taskDetails, Boolean.FALSE);
        List<AppCheckTaskVo.PointTaskGroup> result = new ArrayList<>();

        Map<Long, List<CheckRecordVo>> group = CollStreamUtil.groupByKey(taskDetailVo, CheckRecordVo::getRiskPointId);
        for (Long pointId : group.keySet()) {
            Collections.sort(group.get(pointId));
            result.add(new AppCheckTaskVo.PointTaskGroup(pointId,group.get(pointId).get(0).getRiskPointName(),group.get(pointId).get(0).getDistrictName(),group.get(pointId)));
        }
        return result;
    }

    private List<AppCheckTaskVo> generateAppSubTimeList(List<CheckRecordVo> appTaskVos, boolean needDetail) {
        if (CollectionUtils.isEmpty(appTaskVos)) {
            return new ArrayList<AppCheckTaskVo>();
        }
        ArrayList<AppCheckTaskVo> resultList = new ArrayList<>();
        // 按周期排序，取最小周期
        Collections.sort(appTaskVos);
        CheckRecordVo taskVo = appTaskVos.get(0);
        String unit = taskVo.getPeriodUnit();
        // 最小频率的单位是'时'，将一天的时间切片
        if (unit.equals(CycleType.H.getValue())) {
            // 执行时间分割动作
            doGenerate(appTaskVos, resultList);
            // 给每个时间片分配任务
            setTaskToSubTime(resultList, appTaskVos, needDetail);
        } else {
            // 如果最小单位不是'时'，不做分割，直接返回一条包含所有任务
            AppCheckTaskVo appCheckTaskVo = new AppCheckTaskVo(DateUtil.beginOfDay(new Date()),DateUtil.endOfDay(new Date()));
            appTaskVos.forEach(each -> {
                // 时间片中存在‘异常’或‘未检’，时间片状态设为‘异常’
                if (each.getAction() != null && (each.getAction().equals(RecordActionType.EX.getValue()) || each.getAction().equals(RecordActionType.UC.getValue()))) {
                    appCheckTaskVo.setStatus(InvestigateSubTimeStatus.NU_NORMAL.getStatus());
                }
            });
            Map<Long, List<CheckRecordVo>> taskMap = CollStreamUtil.groupByKey(appTaskVos, CheckRecordVo::getRiskPointId);
            for (Long pointId : taskMap.keySet()) {
                Collections.sort(taskMap.get(pointId));
                appCheckTaskVo.getPointTaskGroups().add(new AppCheckTaskVo.PointTaskGroup(pointId,taskMap.get(pointId).get(0).getRiskPointName(),taskMap.get(pointId).get(0).getDistrictName(),taskMap.get(pointId)));
            }
            resultList.add(appCheckTaskVo);
        }
        return resultList;
    }

    // 生成时间片
    private void doGenerate(List<CheckRecordVo> appTaskVos, ArrayList<AppCheckTaskVo> resultList) {
        DateTime nextGenTime = DateUtil.beginOfDay(new Date());
        Date todayBegin = nextGenTime;
        DateTime end = DateUtil.endOfDay(new Date());

        // 获取当天所有任务的开始时间，排序、去重
        List<Date> checkDateList = appTaskVos.stream().map(CheckRecordVo::getCheckDate).distinct().sorted().collect(Collectors.toList());
        List<Date> beforeToday = checkDateList.stream().filter(e -> e.before(todayBegin)).collect(Collectors.toList());
        List<Date> onToday = checkDateList.stream().filter(e -> e.after(todayBegin) || e.equals(todayBegin)).collect(Collectors.toList());
        // 按最小时间频率生成时间片
        int index = 0;
        // 存在前一天开始延续到今天的，且今天无从零点开始的任务
        if (CollectionUtil.isNotEmpty(beforeToday) && (CollectionUtil.isEmpty(onToday) || !onToday.get(0).equals(todayBegin))) {
            AppCheckTaskVo appCheckTaskVo = new AppCheckTaskVo();
            appCheckTaskVo.setIndex(index++);
            appCheckTaskVo.setStartTime(new Date(nextGenTime.getTime()));
            appCheckTaskVo.setEndTime(CollectionUtil.isEmpty(onToday) ? end : onToday.get(0));
            resultList.add(appCheckTaskVo);
        }
        if (CollectionUtil.isNotEmpty(onToday)) {
            // 生成最后一个时间片外的所有时间片
            for (int i = 0; i < onToday.size() - 1; i++) {
                AppCheckTaskVo appCheckTaskVo = new AppCheckTaskVo();
                appCheckTaskVo.setIndex(index++);
                appCheckTaskVo.setStartTime(new Date(onToday.get(i).getTime()));
                appCheckTaskVo.setEndTime(new Date(onToday.get(i + 1).getTime()));
                resultList.add(appCheckTaskVo);
            }
            // 最后一个时间片，到今天的最后一刻
            AppCheckTaskVo appCheckTaskVo = new AppCheckTaskVo();
            appCheckTaskVo.setIndex(index++);
            appCheckTaskVo.setStartTime(new Date(onToday.get(onToday.size() - 1).getTime()));
            appCheckTaskVo.setEndTime(end);
            resultList.add(appCheckTaskVo);
        }
    }

    private void setTaskToSubTime(List<AppCheckTaskVo> subTimeList, List<CheckRecordVo> taskList, boolean needDetail) {
        // 将任务放入对应的时间
        for (int i = subTimeList.size() - 1;i >= 0;i--) {
            AppCheckTaskVo subTime = subTimeList.get(i);
            Long subStart = subTime.getStartTime().getTime();
            Long subEnd = subTime.getEndTime().getTime();
            Range<Long> subRange = Range.closedOpen(subStart, subEnd);
            for (int j = taskList.size() - 1; j >= 0;j--) {
                CheckRecordVo task = taskList.get(j);
                Long taskStart = task.getCheckDate().getTime();
                Long taskDead = task.getDeadline().getTime();
                if (task.getCheckFinishDate() != null) {
                    // 任务已做，存在两种可能，1：正常排查，2：未检，由定时任务生成'未检'记录 只放入实际完成的那个时间片
                    if (Range.openClosed(subStart,subEnd).contains(task.getCheckFinishDate().getTime()) && !task.isHasUsed()) {
                        subTime.getTaskIds().add(task.getTaskId());
                        subTime.getTasks().add(task);
                        // 异常或未检或签到异常，将影响到当前时间片状态
                        if (RecordActionType.EX.getValue().equals(task.getAction()) || RecordActionType.UC.getValue().equals(task.getAction()) || VerifyState.ABNORMAL.getState().equals(task.getVerifyState())) {
                            subTime.setStatus(InvestigateSubTimeStatus.NU_NORMAL.getStatus());
                        }
                        // 已做的任务只出现一次
                        task.setHasUsed(true);
                    }
                }else {
                    // 任务未做 已过时的时间片(时间片右边界小于当前时间)不放
                    // 符合：[任务开始时间在时间片内) || (任务截止时间在时间片内) || (任务周期跨越了整个时间片)
                    if (subEnd > System.currentTimeMillis() && ((subRange.contains(taskStart) || Range.open(subStart, subEnd).contains(taskDead) || (taskStart < subStart && taskDead >= subEnd)))) {
                        subTime.getTaskIds().add(task.getTaskId());
                        subTime.getTasks().add(task);
                    }
                }
            }
            // 当前时间片中无任务，移除当前时间片
            if (subTime.getTaskIds().size() == 0) {
                subTimeList.remove(subTime);
                continue;
            }
            // 当放入的任务未影响到时间片状态时，表示该时间片下所有任务都未做，此时时间片状态：正常 | 未开始
            if (StringUtils.isBlank(subTime.getStatus())) {
                if (subTime.getStartTime().after(new Date())) {
                    subTime.setStatus(InvestigateSubTimeStatus.NOT_STARTED.getStatus());
                }else {
                    subTime.setStatus(InvestigateSubTimeStatus.NORMAL.getStatus());
                }
            }
            if (canEnter(subTime)) {
                subTime.setStatus(InvestigateSubTimeStatus.CAN_ENTER_CHECK.getStatus());
            }
        }
        // 将时间片内的任务按风险点分组
        groupTaskByPoint(subTimeList, needDetail);
    }

    // 当前时间内在时间片范围内，且时间片内有任务未做，app显示"进入排查"
    private boolean canEnter(AppCheckTaskVo subTime) {
        // 当前时间不在时间范围，不可进入排查
        if (subTime.getStartTime().getTime() > System.currentTimeMillis() || subTime.getEndTime().getTime() < System.currentTimeMillis()) {
            return false;
        }
        List<CheckRecordVo> tasks = subTime.getTasks();
        if (CollectionUtil.isNotEmpty(tasks)) {
            // 存在RecordId为空，即是可排查
            List<CheckRecordVo> unCheckTask = tasks.stream().filter(each -> each.getRecordId() == null).collect(Collectors.toList());
            return unCheckTask.size() > 0;
        }
        return false;
    }

    private void groupTaskByPoint(List<AppCheckTaskVo> subTimeList, boolean needDetail) {
        for (AppCheckTaskVo subTime : subTimeList) {
            if (needDetail) {
                Map<Long, List<CheckRecordVo>> group = CollStreamUtil.groupByKey(subTime.getTasks(), CheckRecordVo::getRiskPointId);
                for (Long pointId : group.keySet()) {
                    Collections.sort(group.get(pointId));
                    subTime.getPointTaskGroups().add(new AppCheckTaskVo.PointTaskGroup(pointId,group.get(pointId).get(0).getRiskPointName(),group.get(pointId).get(0).getDistrictName(),group.get(pointId)));
                }
            }
            subTime.setTasks(null);
        }
    }

    /**
     * 未检(超时未检)、正常(隐患整改)
     * @param recordDtos
     */
    public void uncheckConvert(List<CheckRecordDto> recordDtos) {
        boolean needAutograph=false;
        BaseConfig config = configService.findFirstConfig(BaseConfigCodes.AUTOGRAPH);
        if (config != null && config.getValue().equals("开启")) {
            needAutograph=true;
        }
        Map<Long, String> map = new HashMap<>();
        if (needAutograph){
            if (CollectionUtils.isNotEmpty(recordDtos)) {
                List<Long> userIds = recordDtos.stream().filter(m ->m.getCheckUserId()!=null&&-1!=m.getCheckUserId()).map(m -> m.getCheckUserId()).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(userIds)) {
                    map=getAutograph(userIds);
                }
            }
        }
        Map<Long, String> finalMap = map;
        boolean needAutograph2 = needAutograph;
        recordDtos.forEach(each -> {
            if (StringUtils.isNotBlank(each.getUncheckReason())) {
                // 未检带上未检原因，正常 拼接异常整改
                each.setAction(each.getAction()+Constant.EN_LEFT_BRACKETS+each.getUncheckReason()+Constant.EN_RIGHT_BRACKETS);
                each.setCheckUserId(null);
                if (RecordActionType.UC.getValue().equals(each.getAction())) {
                    // 正常（异常整改）的不需要完成时间
                    each.setCheckFinishDate(null);
                }
            }
            if (needAutograph2){
                each.setAutograph(finalMap.get(each.getCheckUserId()));
            }
        });
    }

    public Map<Long, String> getAutograph(List<Long> userIds) {
        Map<Long, String> map = new HashMap<>();
        List<BaseUser> list = baseUserDao.getAllByIdsAndShowState(userIds);
        for (BaseUser user : list) {
            if (map.get(user.getId()) == null) {
                map.put(user.getId(), user.getAutograph());
            }
        }
        return map;
    }

    public List<CheckRecordVo> convertDtoToVoBatch(List<CheckRecordDto> recordDtos, boolean isHistory) {
        if (!CollectionUtils.isEmpty(recordDtos)) {
            List<CheckRecordVo> checkRecordVos = new ArrayList<>();
            // 任务->assignUser映射
            List<Long> taskIds = recordDtos.stream().map(CheckRecordDto::getTaskId).collect(Collectors.toList());
            List<SimpleTaskAssign> simpleAssign;
            if (isHistory) {
                // 历史
                simpleAssign = CollectionUtil.isNotEmpty(taskIds) ? bpInvestigateTaskAssignService.getHistoryUserIdByTaskIds(taskIds) : new ArrayList<>();
            } else {
                simpleAssign = CollectionUtil.isNotEmpty(taskIds) ? bpInvestigateTaskAssignService.getUserIdByTaskIds(taskIds) : new ArrayList<>();
            }
            Map<Long, List<SimpleTaskAssign>> taskAssignMapping = simpleAssign.stream().collect(Collectors.groupingBy(SimpleTaskAssign::getTaskId));
            // 管控层级映射
            Set<Long> measureTypeIds = recordDtos.stream().filter(e->e.getRiskMeasureTypeId() != null).map(CheckRecordDto::getRiskMeasureTypeId).collect(Collectors.toSet());
            Map<Long, RiskMeasureTypeNode> allMeasureTypeMapping = CollectionUtil.isNotEmpty(measureTypeIds) ? riskMeasureTypeService.getAllTreeMapping(measureTypeIds) : new HashMap<>();
            // 任务完成人映射
            List<Long> checkUserIds = recordDtos.stream().filter(e -> e.getCheckUserId() != null && e.getCheckUserId() != -1).map(CheckRecordDto::getCheckUserId).collect(Collectors.toList());
            List<BaseUser> checkUsers = CollectionUtil.isNotEmpty(checkUserIds) ? baseUserDao.getAllByIds(checkUserIds) : new ArrayList<>();
            Map<Long, BaseUser> checkUserMapping = checkUsers.stream().collect(Collectors.toMap(BaseUser::getId, r -> r));

            recordDtos.forEach(each -> {
                CheckRecordVo checkRecordVo = new CheckRecordVo();
                BeanUtils.copyProperties(each, checkRecordVo);
                // 排查人员从wwyt_bp_investigate_task_assign表里面拿
                List<SimpleTaskAssign> assignList = taskAssignMapping.get(each.getTaskId());
                if (!CollectionUtils.isEmpty(assignList)) {
                    checkRecordVo.setExecutors(convertUserToSimple(assignList));
                }
                if (each.getRiskMeasureTypeId() != null) {
                    checkRecordVo.setRiskMeasureTypeNode(allMeasureTypeMapping.get(each.getRiskMeasureTypeId()));
                }
                // 排查完成人员
                if (each.getCheckUserId() != null && each.getCheckUserId() != -1) {
                    BaseUser finisher = checkUserMapping.get(each.getCheckUserId());
                    if (finisher != null) {
                        checkRecordVo.setFinisher(new KLMapping(finisher.getRealName(), finisher.getId()));
                    }
                }
                if (StringUtils.isBlank(each.getAction())) {
                    // 无检查记录，且计划失效，设置状态为"隐患"
                    if (Constant.COMMON_SWITCH_ON.equals(each.getPlanInvalidFlag())) {
                        checkRecordVo.setAction(RecordActionType.HD.getValue());
                    }
                }
                // 未检，不展示完成时间
                if (RecordActionType.UC.getValue().equals(each.getAction())) {
                    checkRecordVo.setCheckFinishDate(null);
                }
                if (StringUtils.isNotBlank(each.getWfProcessStatus())) {
                    checkRecordVo.setFlowHandelState(each.getWfProcessStatus());
                }
                checkRecordVos.add(checkRecordVo);
            });
            return checkRecordVos;
        }
        return null;
    }

    List<CheckRecordVo> castDtoToVo(List<CheckRecordDto> recordDtos) {
        if (!CollectionUtils.isEmpty(recordDtos)) {
            List<CheckRecordVo> checkRecordVos = new ArrayList<>();
            recordDtos.forEach(each -> {
                CheckRecordVo vo = new CheckRecordVo();
                BeanUtils.copyProperties(each,vo);
                checkRecordVos.add(vo);
            });
            return checkRecordVos;
        }
        return new ArrayList<>();
    }

    List<SimpleSelectListBean> convertUserToSimple(List<SimpleTaskAssign> assignList) {
        ArrayList<SimpleSelectListBean> simpleUsers = new ArrayList<>();
        assignList.forEach(each -> simpleUsers.add(new SimpleSelectListBean(each.getUserId(), each.getUserName())));
        return simpleUsers;
    }

    @Override
    public Map<String, Long> getTaskSummaryCount(TaskSummarySearchBean searchBean) {
        searchBean.setCheckDate(new Date());
        builderSearchParam(searchBean);
        Long userId = Context.getCurrentUser().getRealUserId();
        String companyCode = Context.getCompanyCode();
        Long tenantId = Context.getCurrentTenantId();
        long taskSummaryCount = summaryMapper.findTaskSummaryCount(userId, searchBean, companyCode, tenantId);
        long recordSummaryCount = summaryMapper.findRecordSummaryCount(userId, null, companyCode, tenantId);
        Map<String, Long> map = new HashMap<>();
        map.put("taskSummaryCount", taskSummaryCount);
        map.put("recordSummaryCount", recordSummaryCount);
        return map;
    }

    @Override
    public List<RiskPointSnapshotVo> getRiskPointSnapshot(RecordSearchBean searchBean) {
        boolean isHistory = searchBean.isHistoryFlag();
        searchBean.setEndOfCheckDate(DateUtil.endOfDay(searchBean.getCheckDate()));
        searchBean.setTenentId(Context.getCurrentTenantId());
        searchBean.setOrgCode(Context.getCompanyCode() + Constant.SQL_LIKE);
        List<Long> taskIds = summaryMapper.getTaskIdsByDateAndUser(searchBean.getCheckDate(), searchBean.getEndOfCheckDate(), searchBean.getUserId(), isHistory);
        if (CollectionUtil.isEmpty(taskIds)) {
            return null;
        }
        List<RiskPointSnapshotVo> riskPointSnapshotVo = summaryMapper.getRiskPointByTaskIds(taskIds, isHistory);

        convertPointLocation(riskPointSnapshotVo, taskIds, isHistory);
        riskPointSnapshotVo.sort(Comparator.comparing(RiskPointSnapshotVo::getLastCheckDate));
        return riskPointSnapshotVo;
    }

    private void convertPointLocation(List<RiskPointSnapshotVo> pointSnapshotVos,List<Long> taskIds, boolean isHistory) {
        pointSnapshotVos.forEach(each -> {
            // 风险点存在位置，做转换，否则使用所在风险区域的位置
            if (StringUtils.isNotBlank(each.getPoints())) {
                FenceData fenceData = new FenceData();
                JSONArray pointArrayJson = JSONArray.parseArray(each.getPoints());
                List<FencePoint> points = pointArrayJson.toJavaList(FencePoint.class);
                fenceData.setPoints(points);
                fenceData.setBuildingId(each.getBuildingId());
                fenceData.setFloorId(each.getFloorId());
                String fenceDataJson = JSONArray.toJSON(fenceData).toString();
                each.setPointLocation(fenceDataJson);
            }else {
                each.setPointLocation(districtDao.getLocationByPointId(each.getPointId()));
            }
            CheckRecordDto checkRecordDto = summaryMapper.findLastPositionCheckRecord(each.getPointId(), taskIds, isHistory);
            if (checkRecordDto != null) {
                CheckRecordVo checkRecordVo = new CheckRecordVo();
                BeanUtils.copyProperties(checkRecordDto,checkRecordVo);
                each.setLastCheckDate(checkRecordVo.getCheckFinishDate());
                // 排查完成人员
                if (checkRecordDto.getCheckUserId() != null && checkRecordDto.getCheckUserId() != -1) {
                    checkRecordVo.setFinisher(new KLMapping(baseUserDao.findById(checkRecordDto.getCheckUserId()).get().getRealName(), checkRecordDto.getCheckUserId()));
                }
                // 检查结论及快照展示颜色
                if (StringUtils.isNotBlank(checkRecordVo.getVerifyState())) {
                    if (VerifyState.NORMAL.getState().equals(checkRecordVo.getVerifyState())) {
                        if (RecordActionType.NM.getValue().equals(checkRecordVo.getAction())) {
                            // 签到正常、定位/nfc刷卡正常
                            checkRecordVo.setCheckVerdict(SnapshotVerdict.NORMAL.getVerdict());
                            // NFC刷卡签到正常
                            if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.SWIPE_SIGN.getCode().equals(checkRecordVo.getSignInMethod())) {
                                checkRecordVo.setViewColor(SnapshotViewColor.GREEN.getColor());
                            }
                            // 二维码签到正常
                            if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.QR_CODE_SIGN.getCode().equals(checkRecordVo.getSignInMethod())) {
                                checkRecordVo.setViewColor(SnapshotViewColor.GREEN.getColor());
                            }
                            // 定位签字正常
                            if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.PERSONNEL_POSITIONING.getCode().equals(checkRecordVo.getSignInMethod())) {
                                checkRecordVo.setViewColor(SnapshotViewColor.BLUE.getColor());
                            }
                        } else if (RecordActionType.EX.getValue().equals(checkRecordVo.getAction())) {
                            // 签字正常，上报异常
                            checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_DANGER.getVerdict());
                            checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                        }
                    }else if (VerifyState.ABNORMAL.getState().equals(checkRecordVo.getVerifyState())) {
                        // 签到异常
                        checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                        if (RecordActionType.NM.getValue().equals(checkRecordVo.getAction())) {
                            // 签到异常，检查结果正常
                            if (StringUtils.isBlank(checkRecordVo.getVerifyLocation())) {
                                // 签到异常，检查结果正常，无位置信息
                                if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.PERSONNEL_POSITIONING.getCode().equals(checkRecordVo.getSignInMethod())) {
                                    // 签到方式为定位签到且无位置信息
                                    checkRecordVo.setViewColor(SnapshotViewColor.GREY.getColor());
                                    checkRecordVo.setCheckVerdict(SnapshotVerdict.NONE_LOCATION_INFO.getVerdict());
                                }
                                if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.SWIPE_SIGN.getCode().equals(checkRecordVo.getSignInMethod())) {
                                    // NFC签到无位置
                                    checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                                    checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_VERIFY.getVerdict());
                                }
                                if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.QR_CODE_SIGN.getCode().equals(checkRecordVo.getSignInMethod())) {
                                    // 二维码签到无位置
                                    checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                                    checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_VERIFY.getVerdict());
                                }
                            } else {
                                // 签到异常，检查结果正常，有位置信息
                                checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_VERIFY.getVerdict());
                            }
                        } else {
                            // 签到异常，检查结果异常
                            if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.PERSONNEL_POSITIONING.getCode().equals(checkRecordVo.getSignInMethod())) {
                                // 定位签到
                                if (StringUtils.isBlank(checkRecordVo.getVerifyLocation())) {
                                    // 无位置信息
                                    checkRecordVo.setViewColor(SnapshotViewColor.GREY.getColor());
                                    checkRecordVo.setCheckVerdict(SnapshotVerdict.NONE_LOCATION_INFO.getVerdict());
                                }else {
                                    // 有位置信息
                                    checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                                    checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_DANGER_VERIFY.getVerdict());
                                }
                            }
                            if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.SWIPE_SIGN.getCode().equals(checkRecordVo.getSignInMethod())) {
                                // 刷卡签到
                                checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                                checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_DANGER_VERIFY.getVerdict());
                            }
                            if (checkRecordVo.getSignInMethod() != null && SignInMethodEnum.QR_CODE_SIGN.getCode().equals(checkRecordVo.getSignInMethod())) {
                                // 刷卡签到
                                checkRecordVo.setViewColor(SnapshotViewColor.ORANGE.getColor());
                                checkRecordVo.setCheckVerdict(SnapshotVerdict.ABNORMAL_DANGER_VERIFY.getVerdict());
                            }
                        }
                    }
                } else {
                    // 未签到,签到方式为不签到或者为web端做的任务
                    checkRecordVo.setCheckVerdict(RecordActionType.NM.getValue().equals(checkRecordVo.getAction()) ? SnapshotVerdict.NORMAL.getVerdict() : SnapshotVerdict.ABNORMAL_DANGER.getVerdict());
                    checkRecordVo.setViewColor(RecordActionType.NM.getValue().equals(checkRecordVo.getAction()) ? SnapshotViewColor.BLUE.getColor() : SnapshotViewColor.ORANGE.getColor());
                }
                each.setLastCheckRecord(checkRecordVo);
                each.setHasChecked(true);
            }
            if (each.getLastCheckDate() == null) {
                each.setLastCheckDate(new Date());
            }
        });
    }

    @Override
    public int updateExceptionProcessResultBatchById(String exceptionProcessResult, List<Long> ids) {
        if (CollectionUtil.isNotEmpty(ids)) {
            return summaryMapper.updateExceptionProcessResultBatchById(exceptionProcessResult, ids);
        }
        return 0;
    }

    /**
     * 兼容从今日记录发起的整改和历史记录发起的整改
     * @param itemId
     */
    @Override
    public void updateSummaryRepairStatusV2(Long itemId) {
        boolean isHistory = false;
        BpInvestigateRecordItem item = recordItemDao.findById(itemId).orElse(null);
        if (null == item) {
            isHistory = true;
            item = investigateHistoryMapper.getHistoryItemById(itemId);
        }
        BpInvestigateRecord record = !isHistory ? recordRepository.getOne(item.getRecordId()) :
                investigateHistoryMapper.getRecordById(item.getRecordId());

        List<Long> assigns = !isHistory ? bpInvestigateTaskAssignService.getUserIdsByTaskId(record.getTaskId()) :
                investigateHistoryMapper.getUserIdsByTaskId(record.getTaskId());

        Date startTime = DateUtil.beginOfDay(record.getCheckFinishDate());
        DateTime endTime = DateUtil.beginOfDay(DateUtil.offsetDay(startTime, 1));
        if (CollectionUtil.isNotEmpty(assigns)) {
            ArrayList<BpInvestigateTaskSummary> summaryList = new ArrayList<>();
            boolean finalIsHistory = isHistory;
            assigns.forEach(assign -> {
                BpInvestigateTaskSummary summary = !finalIsHistory ? summaryMapper.getByDateAndUserId(startTime,endTime,assign) :
                        investigateHistoryMapper.getByDateAndUserId(startTime,endTime,assign);
                if (null != summary) {
                    List<String> exceptionProcessList = !finalIsHistory ? summaryMapper.findExceptionProcessResult(startTime,endTime,assign,itemId):
                            investigateHistoryMapper.findExceptionProcessResult(startTime, endTime, assign, itemId);
                    // 走到此方法说明至少有一个异常，若存在"未整改"则汇总应是“等待处理”,不存在则是“已处理”
                    if (CollectionUtil.isNotEmpty(exceptionProcessList) && exceptionProcessList.contains(RepairStatus.NOT_RECTIFIED.getDesc())) {
                        summary.setExceptionProcessResult(RepairStatus.WAITING_FOR_PROCESSING.getDesc());
                    }else {
                        summary.setExceptionProcessResult(RepairStatus.PROCESSED.getDesc());
                    }
                    summaryList.add(summary);
                }
            });

            Map<String, List<BpInvestigateTaskSummary>> summaryMap = summaryList.stream().collect(Collectors.groupingBy(BpInvestigateTaskSummary::getExceptionProcessResult));
            // 此处只更新一个字段，且该字段只有两个值（即“等待处理”，“已处理”）。可直接手写update，最多执行两次。避免使用updateBatch全量更新
            summaryMap.entrySet().forEach(entry -> {
                List<Long> summaryIds = entry.getValue().stream().map(BpInvestigateTaskSummary::getId).collect(Collectors.toList());
                if (!finalIsHistory) {
                    updateExceptionProcessResultBatchById(entry.getKey(), summaryIds);
                }else {
                    if (CollectionUtil.isNotEmpty(summaryIds)) {
                        investigateHistoryMapper.updateExceptionProcessResultBatchById(entry.getKey(), summaryIds);
                    }
                }
            });


        }

    }

    @Override
    public Map<String,Object> moveDataTest(int count) {
        Map<String,Object> map = new HashMap<>();
        Set<Long> set = new HashSet<>();
        long startTime = System.currentTimeMillis();
        for (int i=0;i<count;i++){
            set.add(YitIdHelper.nextId());
        }
        log.info("===============生成耗时================="+(System.currentTimeMillis()-startTime)+"ms");
        log.info("===============生成数据量================="+set.size());
        map.put("生成耗时(ms)",System.currentTimeMillis()-startTime);
        map.put("生成ID数量", set.size());
        return map;
    }

    @Override
    public NfcCheckTaskVO getNfcTaskGroupApp(String nfcCode) {
        List<Long> pointIds = riskPointDao.findByNfc(nfcCode)
                .stream()
                .map(RiskPoint::getId)
                .collect(Collectors.toList());

        return _getTaskGroupByPointIds(pointIds);
    }

    @Override
    public NfcCheckTaskVO getQrCodeTaskGroupApp(String code) {
        List<Long> pointIds = Lists.newArrayList(Long.parseLong(code));
        List<RiskPoint> validPoints = riskPointDao.findByIdsNotDeleted(new HashSet<>(pointIds));
        List<Long> validIds = validPoints.stream()
                .filter(p -> p.getSignInMethod() != null && p.getSignInMethod().equals(SignInMethodEnum.QR_CODE_SIGN.getCode()))
                .map(RiskPoint::getId)
                .collect(Collectors.toList());
        return _getTaskGroupByPointIds(validIds);
    }

    private NfcCheckTaskVO _getTaskGroupByPointIds(List<Long> pointIds) {
        NfcCheckTaskVO res = new NfcCheckTaskVO();
        if (pointIds.size() == 0) {
            res.setStatus("no_risk_points");
            return res;
        }

        long now = System.currentTimeMillis();
        RecordSearchBean todaySearchBean = new RecordSearchBean();
        todaySearchBean.setUserId(Context.getCurrentUserId());
        todaySearchBean.setCycleTypes(Lists.newArrayList("时"));
        todaySearchBean.setRiskPointIds(pointIds);
        List<AppCheckTaskVo> todayTask = this.getAppSubTimeTask(todaySearchBean);
        List<Long> currentTaskIds = todayTask.stream()
                .filter(t -> t.getStartTime().getTime() <= now && t.getEndTime().getTime() >= now)
                .flatMap(t -> t.getTaskIds().stream())
                .collect(Collectors.toList());

        List<AppCheckTaskVo.PointTaskGroup> groups = Lists.newArrayList();
        if (currentTaskIds.size() > 0) {
            groups.addAll(this.getTaskIdsById(currentTaskIds));
        }

        RecordSearchBean weekMonthYearSearchBean = new RecordSearchBean();
        weekMonthYearSearchBean.setUserId(Context.getCurrentUserId());
        weekMonthYearSearchBean.setRiskPointIds(pointIds);
        weekMonthYearSearchBean.setCycleTypes(Lists.newArrayList("日", "周"));
        List<AppCheckTaskVo> week = this.getAppSubTimeTask(weekMonthYearSearchBean);
        List<AppCheckTaskVo.PointTaskGroup> weekGroup = week.stream()
                .filter(t -> t.getStartTime().getTime() <= now && t.getEndTime().getTime() >= now)
                .flatMap(t -> t.getPointTaskGroups().stream())
                .collect(Collectors.toList());
        groups.addAll(weekGroup);

        weekMonthYearSearchBean.setCycleTypes(Lists.newArrayList("月"));
        List<AppCheckTaskVo> month = this.getAppSubTimeTask(weekMonthYearSearchBean);
        List<AppCheckTaskVo.PointTaskGroup> monthGroup = month.stream()
                .filter(t -> t.getStartTime().getTime() <= now && t.getEndTime().getTime() >= now)
                .flatMap(t -> t.getPointTaskGroups().stream())
                .collect(Collectors.toList());
        groups.addAll(monthGroup);

        weekMonthYearSearchBean.setCycleTypes(Lists.newArrayList("年"));
        List<AppCheckTaskVo> year = this.getAppSubTimeTask(weekMonthYearSearchBean);
        List<AppCheckTaskVo.PointTaskGroup> yearGroup = year.stream()
                .filter(t -> t.getStartTime().getTime() <= now && t.getEndTime().getTime() >= now)
                .flatMap(t -> t.getPointTaskGroups().stream())
                .collect(Collectors.toList());
        groups.addAll(yearGroup);

        // 去掉已经完成的任务和组
        Iterator<AppCheckTaskVo.PointTaskGroup> iter = groups.iterator();
        while (iter.hasNext()) {
            AppCheckTaskVo.PointTaskGroup group = iter.next();
            List<CheckRecordVo> unfinishedTasks = group.getTaskList().stream()
                    .filter(t -> "未完成".equals(t.getTaskStatus()) && t.getAction() == null)
                    .collect(Collectors.toList());
            if (unfinishedTasks.size() == 0) {
                iter.remove();
            } else {
                group.setTaskList(unfinishedTasks);
            }
        }

        if (groups.size() == 0) {
            long futureTaskCnt = todayTask.stream()
                    .filter(t -> t.getStartTime().getTime() > now)
                    .filter(t -> InvestigateSubTimeStatus.NOT_STARTED.getStatus().equals(t.getStatus()))
                    .count();
            res.setStatus(futureTaskCnt == 0 ? "no_task" : "future_task");
        } else {
            res.setStatus("success");
        }
        res.setPointTaskGroups(groups);
        return res;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void moveTaskSub(List<Long> taskIds) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return;
        }
        long resultCount = taskMapper.copyTaskToHistoryByIds(taskIds);
        // moveAssign
        moveAssign(taskIds);
        // moveRecord
        moveRecord(taskIds);
        //查询迁移成功
        if ((long) taskIds.size() == resultCount){
            taskMapper.deleteTaskByIds(taskIds);
        }
    }

    /**
     * 迁移任务分配人数据
     * @param taskIds
     */
    private void moveAssign(List<Long> taskIds) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return;
        }
        List<Long> assignIds = assignMapper.getIdByTaskId(taskIds);
        if (CollectionUtil.isNotEmpty(assignIds)) {
            List<List<Long>> assignList = Lists.partition(assignIds,1000);
            for (List<Long> ids : assignList){
                long resultCount = assignMapper.copyAssignToHistoryByIds(ids);
                //查询是否成功
                if ((long) ids.size() == resultCount){
                    assignMapper.deleteByIds(ids);
                }
            }
        }
    }

    /**
     * 迁移记录数据
     * @param taskIds
     * @return
     */
    private void moveRecord(List<Long> taskIds) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return;
        }
        List<Long> recordIds = taskMapper.getRecordIdByTaskIds(taskIds);
        if(CollectionUtil.isNotEmpty(recordIds)) {
            long resultCount = taskMapper.copyRecordToHistoryByIds(recordIds);
            if ((long) recordIds.size() == resultCount){
                taskMapper.deleteRecordByIds(recordIds);
            }
            // moveRecordItem
            moveRecordItem(recordIds);
        }
    }

    /**
     * 迁移记录详情数据
     * @param recordIds
     */
    private void moveRecordItem(List<Long> recordIds) {
        if (CollectionUtil.isEmpty(recordIds)) {
            return;
        }
        List<Long> recordItemIds = taskMapper.getRecordItemIdByRecordIds(recordIds);
        if (CollectionUtil.isNotEmpty(recordItemIds)) {
            long resultCount = taskMapper.copyRecordItemToHistoryByIds(recordItemIds);
            if ((long) recordItemIds.size() == resultCount){
                taskMapper.deleteRecordItemByIds(recordItemIds);
            }
        }
    }

    /**
     * 迁移汇总数据
     * @param border
     */
    @Override
    public void moveSummary(Date border) {
        List<Long> summaryIds = summaryMapper.getIdByDate(border);
        if (CollectionUtil.isNotEmpty(summaryIds)) {
            long resultCount = summaryMapper.copySummaryToHistoryByIds(summaryIds);
            if ((long) summaryIds.size() == resultCount) {
                summaryMapper.deleteSummaryByIds(summaryIds);
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void doMoveHisTaskSub(List<Long> taskIds, String year) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return;
        }
        long resultCount = taskHisMapper.copyHisTaskToYearTaskByIds(taskIds, year);
        // moveHisAssign
        moveHisAssign(taskIds, year);
        // moveHisRecord
        moveHisRecord(taskIds, year);
        //查询迁移成功
        if ((long) taskIds.size() == resultCount) {
            taskHisMapper.deleteHisTaskByIds(taskIds);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void doMoveHisSummary(List<Long> summaryIds, String year) {
        if (CollectionUtil.isEmpty(summaryIds)) {
            return;
        }
        long resultCount = taskSummaryHisMapper.copyHisSummaryToYearSummaryByIds(summaryIds, year);
        // 查询迁移成功
        if ((long) summaryIds.size() == resultCount) {
            taskSummaryHisMapper.deleteHisSummaryByIds(summaryIds);
        }

    }

    private void moveHisRecord(List<Long> taskIds, String year) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return;
        }
        List<Long> recordIds = taskHisMapper.getHisRecordIdByHisTaskIds(taskIds);
        if (CollectionUtil.isNotEmpty(recordIds)) {
            long resultCount = taskMapper.copyHisRecordToYearRecordByIds(recordIds, year);
            if ((long) recordIds.size() == resultCount) {
                taskMapper.deleteHisRecordByIds(recordIds);
            }
            // moveHisRecordItem
            moveHisRecordItem(recordIds, year);
        }
    }

    private void moveHisRecordItem(List<Long> recordIds, String year) {
        if (CollectionUtil.isEmpty(recordIds)) {
            return;
        }
        List<Long> recordItemIds = taskMapper.getHisRecordItemIdByRecordIds(recordIds);
        if (CollectionUtil.isNotEmpty(recordItemIds)) {
            long resultCount = taskMapper.copyHisRecordItemToYearRecordItemByIds(recordItemIds, year);
            if ((long) recordItemIds.size() == resultCount) {
                taskMapper.deleteHisRecordItemByIds(recordItemIds);
            }
        }
    }

    private void moveHisAssign(List<Long> taskIds, String year) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return;
        }
        List<Long> assignIds = assignMapper.getHisAssignIdByTaskId(taskIds);
        if (CollectionUtil.isNotEmpty(assignIds)) {
            List<List<Long>> assignList = Lists.partition(assignIds, 1000);
            for (List<Long> ids : assignList) {
                long resultCount = assignMapper.copyHisAssignToYearAssignByIds(ids, year);
                //查询是否成功
                if ((long) ids.size() == resultCount) {
                    assignMapper.deleteHisAssignByIds(ids);
                }
            }
        }
    }

}
